package com.hl.card.credit.pub.common;

import java.util.Random;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * 
    * @ClassName: RedisLock
    * @Description: TODO(redis lock)
    * @author wdf
    * @date 2018年3月25日
    *
 */
public class RedisLock {

	/** 加锁标志 */
	public static final String LOCKED = "TRUE";
	/** 毫秒与毫微秒的换算单位 1毫秒 = 1000000毫微秒 */
	public static final long MILLI_NANO_CONVERSION = 1000 * 1000L;
	/** 默认超时时间（毫秒） */
	public static final long DEFAULT_TIME_OUT = 1000;
	public static final Random RANDOM = new Random();
	/** 锁的超时时间（秒），过期删除 */
	public static final int EXPIRE = 3 * 60;

	private JedisPool jedisPool;
	private Jedis jedis;
	private String key;
	// 锁状态标志
	private boolean locked = false;

	/**
	 * This creates a RedisLock
	 * 
	 * @param key
	 *            key
	 * @param shardedJedisSentinelPool
	 *            数据源
	 */
	public RedisLock(String key,
			JedisPool jedisPool) {
		this.key = key + "_lock";
		this.jedisPool = jedisPool;
		this.jedis = this.jedisPool.getResource();
	}

	public Jedis getJedis() {
		return jedis;
	}

	/**
	 * 加锁 应该以： lock(); try { doSomething(); } finally { unlock()； } 的方式调用
	 * 
	 * @param timeout
	 *            超时时间
	 * @return 成功或失败标志
	 */
	public boolean lock(long timeout) {
		long nano = System.nanoTime();
		timeout *= MILLI_NANO_CONVERSION;
		try {
			while ((System.nanoTime() - nano) < timeout) {
				if (this.jedis.setnx(this.key, LOCKED) == 1) {
					this.jedis.expire(this.key, EXPIRE);
					this.locked = true;
					return this.locked;
				}
				// 短暂休眠，避免出现活锁
				Thread.sleep(3, RANDOM.nextInt(500));
			}
		} catch (Exception e) {
			throw new RuntimeException("Locking error", e);
		}
		return false;
	}

	/**
	 * 加锁 应该以： lock(); try { doSomething(); } finally { unlock()； } 的方式调用
	 * 
	 * @param timeout
	 *            超时时间
	 * @param expire
	 *            锁的超时时间（秒），过期删除
	 * @return 成功或失败标志
	 */
	public boolean lock(long timeout, int expire) {
		long nano = System.nanoTime();
		timeout *= MILLI_NANO_CONVERSION;
		try {
			while ((System.nanoTime() - nano) < timeout) {
				if (this.jedis.setnx(this.key, LOCKED) == 1) {
					this.jedis.expire(this.key, expire);
					this.locked = true;
					return this.locked;
				}
				// 短暂休眠，避免出现活锁
				Thread.sleep(3, RANDOM.nextInt(500));
			}
		} catch (Exception e) {
			throw new RuntimeException("Locking error", e);
		}
		return false;
	}

	/**
	 * 加锁 应该以： lock(); try { doSomething(); } finally { unlock()； } 的方式调用
	 * 
	 * @return 成功或失败标志
	 */
	public boolean lock() {
		return lock(DEFAULT_TIME_OUT);
	}

	/**
	 * 解锁 无论是否加锁成功，都需要调用unlock 应该以： lock(); try { doSomething(); } finally {
	 * unlock()； } 的方式调用
	 */
	public void unlock() {
		try {
			if (this.locked) {
				this.jedis.del(this.key);
			}
		} finally {
			this.jedisPool.returnResource(this.jedis);
		}
	}

	/***
	 * 获取下一个用户id
	 * 
	 * @param shardedJedisSentinelPool
	 * @return
	 */
	public static Integer getUserId() {
		JedisPool jedisPool=RedisClient.getJedisPool();
		String MaxUserId = RedisKey.MaxUserId;
		RedisLock l = new RedisLock(MaxUserId, jedisPool);
		l.lock();
		Integer userId = null;
		try {
			/* 获取用户id */
			String s = l.jedis.get(MaxUserId);
			if (s != null) {
				userId = Integer.parseInt(s);
				/* 生成下一个id */
				l.jedis.set(MaxUserId, (userId + 1) + "");
			}
		} finally {
			l.unlock();
		}
		return userId;
	}

	/***
	 * 生成下一个用户id
	 * 
	 * @param shardedJedisSentinelPool
	 * @return
	 */
	public static void setUserId(Integer user_id) {
		JedisPool jedisPool = RedisClient.getJedisPool();
		RedisLock l = new RedisLock("MaxUserId", jedisPool);
		l.lock();
		try {
			String s = l.jedis.get("MaxUserId");
			l.jedis.set("MaxUserId", user_id.toString());
		} finally {
			l.unlock();
		}
	}
}
